/*
 *  \file Curl.h
 *  GRE
 *
 *  Created by Kutlak Roman on 19/10/2011.
 *  Copyright 2011 Kutlak Roman. All rights reserved.
 *
 */

#ifndef Curl_h 
#define Curl_h

#include "curl/curl.h"

#include <mutex>

namespace kutlak {
namespace roman {
namespace gre {
    
#define CURL_DEBUG 0
    
    /*!
     * \brief This class encapsulates the C curl library. 
     *  
     *  #include "curl/curl.h" <BR> 
     *  -lcurl 
     * 
     *  The class is a wraper around a CURL*. Each instance of the class
     *  maintains it's own CURL* that is used for sending http/ftp requests.
     *  
     *  The first created instance calls curl_global_init() and the last 
     *  destroyed instance calls curl_global_cleanup().
     *
     *  In multithreaded environment one should create a static instance
     *  of Curl (to call the global init) before any other threads are created.
     *  Similarly, the call to global cleanup should happen when there
     *  is only a single thread (i.e., the main thread).
     *
     *  The wrapper is very simple. It uses the basic settings and there
     *  is no way of changing it...at the moment.
     *  
     * @see http://curl.haxx.se/libcurl/c/ for more information. 
     */
    class Curl
    {
    public:
#pragma mark -
#pragma mark lifecycle
        /*! \brief Default constructor. 
         *  The constructor can throw as std::runtime_error
         *  if the initialization fails.
         */
        Curl();
        
        Curl(const Curl& from) = delete;
        Curl& operator=(const Curl& from) = delete;
        
        //! Destructor.
        ~Curl(void);
        
#pragma mark -
#pragma mark operations
        
        /*! \brief Method takes an URL and performs the request.
         *  Method throws std::runtime_error with the error message on failure.
         *  \param url to retrieve.
         *  \return the result of the request (HTML code).
         */
        std::string Request(const std::string& url);
        
#pragma mark -
#pragma mark enquiry
        
        //! Returns the result of the last request.
        const std::string& Result() const;
        
        //! Returns the last error message.
        std::string ErrorMessage() const;
        
        //! Returns the last error code.
        CURLcode ErrorCode() const;
        
        //! Returns the number of requests performed.
        static size_t Requests();
        
        //! Replaces HTML escape codes by the corresponding chars.
        std::string Unescape(const std::string& str);
        
    private:
        //! Init method that sets the default parameters.
        void Init();

        //! This method is used as the curl callback function.
        static int Writer(char *data, size_t size, size_t nmemb, std::string *buffer);
        
#pragma mark -
#pragma mark data
        CURL* mpCurl;                         //! Pointer to the connection
        CURLcode mErrorCode;                  //! Last error code.
        std::string mResultBuffer;            //! Bufer for the actual result of the query
        char mErrorBuffer[CURL_ERROR_SIZE];   //! Buffer for the errors returned by curl
        
        static size_t sActiveInstances; //! static variable for tracking instances
        static size_t snRequests;       //! static variable to keep track of requests
        static std::mutex sMutex;
    };
    
} // end namespace gre
}
}
#endif // Curl_h
